package com.naiterui.ehp.bp.support.config;

import feign.Util;
import feign.codec.Decoder;
import feign.codec.ErrorDecoder;
import java.io.IOException;
import java.lang.reflect.Type;

import org.springframework.context.annotation.Bean;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.naiterui.ehp.bp.support.exception.BaseExceptionCodes;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.support.exception.ResponseVO;
import com.naiterui.ehp.bp.support.utils.JsonMapper;

import lombok.extern.slf4j.Slf4j;

/**
 * 此配置会解析ResponseVO中的data， 如果确定返回值为Object，那么可直接用对象接受，可不使用List，
 * 如果需要抛出异常，那么直接在feign定义的方法throws BusinessException，即可捕获到对应异常
 *
 * @author 王泽浩
 * @date 2019-05-31 10:15
 * @since 1.0.0
 */
@Slf4j
public class FeignConfiguration {

    @Bean
    public Decoder decoder() {
        return (response, type) -> {
            String json = Util.toString(response.body().asReader());
            log.debug("feign调用返回对象：json={}", json);
            ResolvableType resolvableType = ResolvableType.forType(type);
            //如果是基本类型，那么获取class，在判断结果是否为null，如果是null，则直接返回
            JavaType resolvableJavaType = this.getJavaType(resolvableType.getType());
            JavaType javaType = this.getJavaType(ResponseVO.class, resolvableJavaType);

            log.debug("feign调用返回对象类型：javaType={}", javaType);
            ResponseVO<Object> responseVO = JsonMapper.toObject(json, javaType);
            if (responseVO.getCode() != BaseExceptionCodes.SUCCESS) {
                log.error("调用接口业务异常 url:{} code:{} msg:{}", response.request().url(), responseVO.getCode(), responseVO.getMsg());
            }
            return responseVO.getData();
        };
    }

    @Bean
    public ErrorDecoder errorDecoder() {
        return (methodKey, response) -> {
            // 获取原始的返回内容
            try {
                String json = Util.toString(response.body().asReader());
                log.error("fegin调用异常处理 请求{} 返回:{}", response.request().toString(), json);
                ResponseVO<Object> responseVO = JsonMapper.toObject(json, new ParameterizedTypeReference<ResponseVO<Object>>() {
                });
                return new BusinessException(responseVO.getCode(), responseVO.getMsg());
            } catch (IOException e) {
                return new BusinessException(BaseExceptionCodes.JSON_ERROR, e);
            }
        };
    }

    private JavaType getJavaType(Type type) {
        return JsonMapper.getJavaType(type);
    }

    @SuppressWarnings("SameParameterValue")
    private JavaType getJavaType(Class<?> collectionClass, JavaType... parameterTypes) {
        TypeFactory typeFactory = JsonMapper.getJsonMapper().getTypeFactory();
        return typeFactory.constructParametricType(collectionClass, parameterTypes);
    }

}
